/*
 * XPlatformInterface.java
 * 
 * Copyright (c) 2006 - 2007
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.xfc.util.platform;

import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.net.URL;

import javax.swing.Action;
import javax.swing.SwingUtilities;

import org.xfc.XApp;
import org.xfc.util.XUtils;
import org.xfc.util.reflect.XReflectClass;
import org.xfc.util.reflect.XReflectObject;
import org.xfc.util.reflect.XReflectProxy;

// TODO: we really should have default About and Quit actions.


/**
 * A Java interface to Macintosh specific functionality.
 * <p>
 * See:
 * <ul>
 *   <li>http://developer.apple.com/technotes/tn/tn2042.html
 *   <li>http://developer.apple.com/releasenotes/Java/java141/system_properties/chapter_4_section_3.html
 * </ul>
 * 
 * @author Devon Carew
 */
public class XMacPlatform
	extends XDefaultPlatform
{
	private XReflectObject macAppObject;
    
	private Action aboutAction;
	private Action preferencesAction;
	private Action quitAction;
	
	private PropertyChangeListener listener = new PropertyChangeListener() {
		public void propertyChange(PropertyChangeEvent event) {
			updateActions();
		}
	};
	
	XMacPlatform(XApp app)
	{
		initProperties(app);
        
		initAppListener();
	}
	
	/**
	 * Sets the app to use the Mac brushed metal look. This needs to be called very earlier in the
	 * applications initialization for the Mac OS to pick up the flag.
	 * 
	 * @param value
	 */
	public void setBrushMetalLook(boolean value)
	{
		System.setProperty("apple.awt.brushMetalLook", Boolean.toString(value));
	}
	
	/**
	 * Sets the app to show the window grow box in the lower right corner of Frames. This needs to be called
	 * very earlier in the applications initialization for the Mac OS to pick up the flag.
	 * 
	 * @param value
	 */
	public void setShowGrowBox(boolean value)
	{
		System.setProperty("apple.awt.showGrowBox", Boolean.toString(value));
	}
	
	public void registerAboutAction(Action action)
	{
		if (aboutAction != null)
			aboutAction.removePropertyChangeListener(listener);
		
		aboutAction = action;
		
		if (aboutAction != null)
			aboutAction.addPropertyChangeListener(listener);
		
		updateActions();
	}
	
	public void registerPreferencesAction(Action action)
	{
		if (preferencesAction != null)
			preferencesAction.removePropertyChangeListener(listener);
		
		preferencesAction = action;
		
		if (preferencesAction == null)
		{
            macAppObject.invoke("removePreferencesMenuItem");
		}
		else
		{
			if (preferencesAction != null)
				preferencesAction.addPropertyChangeListener(listener);
			
            macAppObject.invoke("addPreferencesMenuItem");
			
			updateActions();
		}
	}
	
	public void registerQuitAction(Action action)
	{
		quitAction = action;
	}
	
	// Browser support

	public void showInBrowser(URL url)
		throws IOException
	{
		XReflectClass fileManager = XReflectClass.createReflectClass("com.apple.eio.FileManager");
		
		fileManager.invokeStatic("openURL", url.toExternalForm());
	}
	
	
	// Implementation
	
	private void initProperties(XApp app)
	{
		System.setProperty("com.apple.mrj.application.apple.menu.about.name", app.getAppName());
        
        System.setProperty("apple.laf.useScreenMenuBar", "true");
        System.setProperty("apple.awt.showGrowBox", "false");
	}
	
	private void initAppListener()
	{
        // We do a lot of slight of hand here so that we don't require mac specific libraries on
        // non-Mac platforms - either at runtime or during the build process.
        XReflectClass   macAppClass = XReflectClass.createReflectClass("com.apple.eawt.Application");
        Class           appListenerClass = XUtils.classForName("com.apple.eawt.ApplicationListener");
        
        macAppObject = XReflectObject.createReflectObject(macAppClass.invokeStatic("getApplication"));
        
        XReflectProxy appListenerHandler = new XReflectProxy()
        {
        	{
        		// This is here to get the IDE to stop complaining about the methods not being called.
        		if (false)
        		{
        			handleAbout(null);
        			handlePreferences(null);
        			handleQuit(null);
        		}
        	}
        	
            public void handleAbout(Object event)
            {
            	XReflectObject eventObject = XReflectObject.createReflectObject(event);
            	eventObject.invoke("setHandled", Boolean.TRUE);
            	invokeAction(aboutAction);
            }
            
            public void handlePreferences(Object event)
            {
            	invokeAction(preferencesAction);
            }
            
            public void handleQuit(Object event)
            {
            	invokeAction(quitAction);
            }
        };
        
        Object appListenerProxy = XReflectProxy.createProxyObject(appListenerClass, appListenerHandler);
        
        macAppObject.invoke("addApplicationListener", appListenerProxy);
	}
	
	private void invokeAction(final Action action)
	{
		if (action == null || !action.isEnabled())
			return;
		
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				action.actionPerformed(new ActionEvent(XApp.getApp(), 0, (String)action.getValue(Action.NAME)));
			}
		});
	}
	
	private void updateActions()
	{
		Boolean aboutEnabled = Boolean.valueOf(aboutAction != null && aboutAction.isEnabled());
		
        if (!aboutEnabled.equals(macAppObject.invoke("getEnabledAboutMenu")))
            macAppObject.invoke("setEnabledAboutMenu", aboutEnabled);
		
		if (preferencesAction != null)
		{
            Boolean prefEnabled = Boolean.valueOf(preferencesAction.isEnabled());
            
			if (!prefEnabled.equals(macAppObject.invoke("getEnabledPreferencesMenu")))
                macAppObject.invoke("setEnabledPreferencesMenu", prefEnabled);
		}
	}
	
}
